package cn.dinkevin.xui.watcher;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

import cn.dinkevin.xui.XUI;
import cn.dinkevin.xui.util.LogUtil;

/**
 * 网络事件监听类
 * Created by chengpengfei on 2017/5/6.
 * Copyright ©2017 juziwl, All Rights Reserved.
 */

public final class NetworkWatcher {

    private NetworkWatcher(){}

    /**
     * 网络连接监听
     */
    public interface NetworkListener {

        /**
         * 是否连接状态更新回调
         * @param isConnected 是否有网络连接
         */
        void onConnectionStateChanged(boolean isConnected);

        /**
         * 网络连接方式更新回调
         * @param isWifi 是否为Wifi
         */
        void onConnectionModeChanged(boolean isWifi);
    }
    private static List<NetworkListener> networkListeners = new ArrayList<>();
    private static ConnectionReceiver connectionReceiver = new ConnectionReceiver();

    /**
     * 开启注册网络监听
     */
    public static void register(){
        IntentFilter filter = new IntentFilter();
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        XUI.getInstance().getContext().registerReceiver(connectionReceiver,filter);
    }

    /**
     * 注销网络监听
     */
    public static void unregister(){
        XUI.getInstance().getContext().unregisterReceiver(connectionReceiver);
    }

    /**
     * 绑定连接状态更新监听
     * @param listener
     */
    public static void addNetworkListener(NetworkListener listener){
        for (int i = 0; i < networkListeners.size();i++){
            NetworkListener lt = networkListeners.get(i);
            if(lt == listener){
                return;
            }
        }
        networkListeners.add(listener);
    }

    /**
     * 删除网络状态监听
     * @param listener
     */
    public static void removeNetworkListener(NetworkListener listener){
        networkListeners.remove(listener);
    }

    /**
     * 当前网络是否已经连接
     * @return
     */
    public static boolean isConnected(){
        if (XUI.getInstance().getContext()==null) return false;

        ConnectivityManager mgr = (ConnectivityManager) XUI.getInstance().getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo;
        try {
            netInfo = mgr.getActiveNetworkInfo();

            return netInfo != null && netInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED;
        } catch (Exception e) {
            LogUtil.e("getActiveNetworkInfo failed.");
        }
        return false;
    }

    /**
     * 当前是否为 WiFi 状态
     * @return
     */
    public static boolean isWifi(){
        if (XUI.getInstance().getContext()==null) return false;
        ConnectivityManager mgr = (ConnectivityManager) XUI.getInstance().getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo;
        try {
            netInfo = mgr.getActiveNetworkInfo();
            if(null != netInfo && netInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED){
                return netInfo.getType() == ConnectivityManager.TYPE_WIFI;
            }
        } catch (Exception e) {
            LogUtil.e("getActiveNetworkInfo failed.");
        }
        return false;
    }

    /**
     * 网络切换监听，客户端通过注册该广播通知mars stn网络切换
     */
    public static class ConnectionReceiver extends BroadcastReceiver {

        public static NetworkInfo lastActiveNetworkInfo = null;
        public static WifiInfo lastWifiInfo = null;
        public static boolean lastConnected = true;

        public static String TAG = "mars.ConnectionReceiver";

        @Override
        public void onReceive(Context context, Intent intent) {
            if (context == null || intent == null) {
                return;
            }

            ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = null;
            try {
                netInfo = mgr.getActiveNetworkInfo();
            } catch (Exception e) {
                Log.i(TAG, "getActiveNetworkInfo failed.");
            }

            checkConnInfo(context, netInfo);
        }

        public void checkConnInfo(final Context context, final NetworkInfo activeNetInfo) {

            if (activeNetInfo == null) {
                lastActiveNetworkInfo = null;
                lastWifiInfo = null;
                for(NetworkListener listener : networkListeners){
                    if(null != listener){
                        listener.onConnectionStateChanged(false);
                    }
                }
            }
            else if (activeNetInfo.getDetailedState() != NetworkInfo.DetailedState.CONNECTED) {

                if (lastConnected) {
                    lastActiveNetworkInfo = null;
                    lastWifiInfo = null;
                    for(NetworkListener listener : networkListeners){
                        if(null != listener){
                            listener.onConnectionStateChanged(true);
                        }
                    }
                }

                lastConnected = false;
            }
            else {
                if (isNetworkChange(context, activeNetInfo)) {
                    for(NetworkListener listener : networkListeners){
                        if(null != listener){
                            listener.onConnectionStateChanged(true);
                        }
                    }
                }
                lastConnected = true;
            }
        }

        public boolean isNetworkChange(final Context context, final NetworkInfo activeNetInfo) {

            if (context==null||activeNetInfo==null) return false;

            boolean isWifi = (activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI);
            if (isWifi) {
                WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                WifiInfo wi = wifiManager.getConnectionInfo();
                if (wi != null &&  null!=lastWifiInfo && null!=wi.getSSID()&&null!=wi.getSSID()
                        && wi.getBSSID().equals(lastWifiInfo.getBSSID())
                        && wi.getSSID().equals(lastWifiInfo.getSSID())
                        && lastWifiInfo.getNetworkId() == wi.getNetworkId()) {
                    Log.w(TAG, "Same Wifi, do not NetworkChanged");
                    return false;
                }
                lastWifiInfo = wi;
            } else if (lastActiveNetworkInfo != null&&activeNetInfo!=null&&null!=lastActiveNetworkInfo.getExtraInfo()
                    && lastActiveNetworkInfo.getExtraInfo() != null && activeNetInfo.getExtraInfo() != null
                    && lastActiveNetworkInfo.getExtraInfo().equals(activeNetInfo.getExtraInfo())
                    && lastActiveNetworkInfo.getSubtype() == activeNetInfo.getSubtype()
                    && lastActiveNetworkInfo.getType() == activeNetInfo.getType()) {
                return false;

            } else if (lastActiveNetworkInfo != null
                    && lastActiveNetworkInfo.getExtraInfo() == null && activeNetInfo.getExtraInfo() == null
                    && lastActiveNetworkInfo.getSubtype() == activeNetInfo.getSubtype()
                    && lastActiveNetworkInfo.getType() == activeNetInfo.getType()) {
                Log.w(TAG, "Same Network, do not NetworkChanged");
                return false;
            }

            for(NetworkListener listener : networkListeners){
                if(null != listener){
                    listener.onConnectionModeChanged(isWifi);
                }
            }

            lastActiveNetworkInfo = activeNetInfo;
            return true;
        }

    }
}
